﻿Imports System.Text.RegularExpressions

Public Class ValidadorDeFormularios
    Private Shared FormatoCorreo As New Regex("^[a-zA-Z0-9_.%+\-()]+@[A-Za-z0-9.-]+\.[a-zA-z]{2,4}$")
    ' Opcion 1 (en uso) igual que opcion 1 pero no acepta numeros como 66. o 66,
    Private Shared FormatoDecimal As New Regex("^-?(0|[1-9]\d*)?([\.,]\d+)?(?<=\d)$")
    'Opcion 2 (no esta en uso) decimal acepta numeros como 66. o 66, o .66 o ,66 
    Private Shared FormatoDecimal2 As New Regex("^-?\d*([,.]\d*)?(?<=\d[,.]?)$")
    'Expresion regular para extraer el numero (tamaño) del nombre del control.
    'En caso de querer especificar un tamaño maximo se debe poner un numero 
    'entre characteres iguales que no sean digitos o espacios vacios. Ejemplo _77_ o l8l
    'en caso de haber mas de un match la expresion regular simpre matchea el ultimo. 
    'Ejemplo intTxt_44_5_ matchea '5'.
    Private Shared ExtraerTamano As New Regex("(?<=\k<p>)\d+(?=(?<p>[^ \d]))", RegexOptions.RightToLeft)
    Private Shared validarTiempo As New Regex("^([0-1][0-9]|2[0-3]):([0-5][0-9])$")
    'Clave segura:
    ' - Que contenga al menos una letra en Mayuscula.
    ' - Que contenga al menos una letra en Minuscula.
    ' - Que contenga al menos un caracter especial.
    ' - Que contenga una longitud como minimo de 8 caracteres.
    ' - Longitud maxima no esta limitada. ^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$
    Private Shared ClaveSegura As New Regex("(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$")  'By WZV
    Private Shared FormatoTelefono As New Regex("^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4,}$")
    Private Frm As Control
    Public WriteOnly Property Control() As Control
        Set(value As Control)
            If (value Is Nothing) Then
                Throw New NullReferenceException()
            End If
            Frm = value
        End Set
    End Property

    Private ErrorPrvdr As ErrorProvider

    Public Sub New(pFrm As Form, pErrorPrvdr As ErrorProvider)
        ' Inicialiso el super
        MyBase.New()
        ' Asigno los valores

        If (pFrm Is Nothing Or pErrorPrvdr Is Nothing) Then
            Throw New NullReferenceException()
        End If
        Me.Frm = pFrm
        Me.ErrorPrvdr = pErrorPrvdr

    End Sub

    ''' <summary>
    ''' Valida el formulario completo
    ''' Durate el proceso se encarga de mostrar los mensajes de error
    ''' </summary>
    ''' <returns>Si formulario paso la validacion</returns>
    ''' <remarks></remarks>
    Public Function ValidarFormulario() As Boolean
        Dim Valido As Boolean = True

        For Each ctrl As Control In Frm.Controls
            Dim aux As Boolean = True

            If TypeOf ctrl Is RichTextBox Then
                aux = ValidarRichTextBox(ctrl)
            ElseIf TypeOf ctrl Is TextBoxBase Then
                aux = ValidarCampoTexto(ctrl)
            ElseIf TypeOf ctrl Is ComboBox Then
                aux = ValidarComboBox(ctrl)
            End If

            If aux = False Then
                Valido = aux
            End If
        Next

        Return Valido
    End Function

    ''' <summary>
    ''' Valida un campo de texto
    ''' </summary>
    ''' <param name="TxtBx">El campo de texto a validar</param>
    ''' <returns>Si el campo de texto es valido</returns>
    ''' <remarks></remarks>
    Public Function ValidarCampoTexto(TxtBx As TextBoxBase) As Boolean
        Dim Valido As Boolean = True
        Dim Nombre As String = TxtBx.Name
        Dim Texto As String = TxtBx.Text.Trim()

        If Not TxtBx.Visible Then
            Return True
        End If

        If Nombre.StartsWith("txtStr") Then

            If Texto.Length = 0 Then
                ErrorPrvdr.SetError(TxtBx, "Campo requerido.")
                Valido = False
            Else
                ErrorPrvdr.SetError(TxtBx, "")
            End If

        ElseIf Nombre.StartsWith("txtInt") Then

            Dim aux As Integer
            If Not Integer.TryParse(Texto, aux) Then
                ErrorPrvdr.SetError(TxtBx, "Solo se aceptan numeros enteros.")
                Valido = False
            Else
                ErrorPrvdr.SetError(TxtBx, "")
            End If

        ElseIf Nombre.StartsWith("txtDec") Then


            If Not FormatoDecimal.IsMatch(Texto) Then
                ErrorPrvdr.SetError(TxtBx, "Solo se aceptan numeros con decimales.")
                Valido = False
            Else
                ErrorPrvdr.SetError(TxtBx, "")
            End If

        ElseIf Nombre.StartsWith("txtEmail") Then

            If Not FormatoCorreo.IsMatch(Texto) Then
                ErrorPrvdr.SetError(TxtBx, "El formato del correo no es valido.")
                Valido = False
            Else
                ErrorPrvdr.SetError(TxtBx, "")
            End If

        ElseIf Nombre.StartsWith("txtHora") Then

            If Not validarTiempo.IsMatch(Texto) Then
                ErrorPrvdr.SetError(TxtBx, "La hora no es valida")
                Valido = False
            Else
                ErrorPrvdr.SetError(TxtBx, "")
            End If
        ElseIf Nombre.StartsWith("txtTelefono") Then

            If Not FormatoTelefono.IsMatch(Texto) Then
                ErrorPrvdr.SetError(TxtBx, "El telefono debe tener alguno de los siguientes formatos: 123-456-7890, (123) 456-7890, 123 456 7890, 123.456.7890 o +91 (123) 456-7890")
                Valido = False
            Else
                ErrorPrvdr.SetError(TxtBx, "")
            End If
        End If

        Return Valido
    End Function

    ''' <summary>
    ''' Valida un combo box
    ''' </summary>
    ''' <param name="CmbBx">El combobox a validar</param>
    ''' <returns>Si el combobox es valido</returns>
    ''' <remarks></remarks>
    Public Function ValidarComboBox(CmbBx As ComboBox) As Boolean
        Dim Valido As Boolean = True

        If CmbBx.Name.StartsWith("cmbReq") Then
            If CmbBx.SelectedItem Is Nothing Then
                ErrorPrvdr.SetError(CmbBx, "Selecione una opcion.")
                Valido = False
            Else
                ErrorPrvdr.SetError(CmbBx, String.Empty)
            End If
        End If

        Return Valido
    End Function

    ''' <summary>
    ''' Valida un campo de texto enriquesido
    ''' </summary>
    ''' <param name="RchTxtBx">El control a validar</param>
    ''' <returns>Si el control tiene contenido</returns>
    ''' <remarks></remarks>
    Public Function ValidarRichTextBox(RchTxtBx As RichTextBox) As Boolean
        Dim Valido As Boolean = True

        If RchTxtBx.Name.StartsWith("rtbStr") Then
            If RchTxtBx.Text = String.Empty Then
                ErrorPrvdr.SetError(RchTxtBx, "Campo requerido.")
                Valido = False
            Else
                ErrorPrvdr.SetError(RchTxtBx, String.Empty)
            End If
        End If

        Return Valido
    End Function

    Public Function ValidarClaveSegura(TxtBx As TextBox) As Boolean
        Dim Valido As Boolean = True
        Dim Texto As String = TxtBx.Text.Trim()

        If Not ClaveSegura.IsMatch(Texto) Then
            ErrorPrvdr.SetError(TxtBx, "Debe ingresar una clave segura" + Chr(13) + "Que contenga al menos una letra mayúscula" + Chr(13) +
                                "Que contenga al menos una letra minúscula" + Chr(13) + "Que contenga al menos un caracter especial" + Chr(13) +
                                "Que contenga una longituda mínima de 8 caracteres."
                                )
            Valido = False
        Else
            ErrorPrvdr.SetError(TxtBx, "")
        End If

        Return Valido
    End Function

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class
